package com.caishi.lkx.exam.service.impl;

import cn.hutool.core.util.StrUtil;
import com.caishi.lkx.exam.mapper.ProductCodeMapper;
import com.caishi.lkx.exam.model.ColumnModel;
import com.caishi.lkx.exam.model.ProductCodeModel;
import com.caishi.lkx.exam.service.ICategoryService;
import com.caishi.lkx.exam.service.IPackageService;
import com.caishi.lkx.exam.service.IPackageSkuService;
import com.caishi.lkx.exam.service.IProductCodeService;
import com.zzw.common.Wrappers;
import com.zzw.common.entity.IBaseMapper;
import com.zzw.common.exception.BizRuntimeException;
import com.zzw.common.lock.RedissonLock;
import com.caishi.lkx.exam.ExamResultCode;
import com.caishi.lkx.exam.ienum.status.ProductCodeStatus;

import com.caishi.lkx.order.model.OrderModel;
import com.caishi.lkx.order.model.UserAssetsDataModel;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class ProductCodeServiceImpl implements IProductCodeService {

    @Resource
    private ProductCodeMapper productCodeMapper;
    @Resource
    private IPackageSkuService packageSkuService;
    @Resource
    private ICategoryService categoryService;

    @Resource
    private IPackageService packageService;

    @Override
    public IBaseMapper<ProductCodeModel, String> getMapper() {
        return productCodeMapper;
    }

    @Override
    public LocalDateTime computeEndTime(OrderModel orderModel, String sourceId, LocalDateTime startTime) {
        return null;
    }

    @Override
    public String orderOnlinePayTitle(OrderModel orderModel, String id) {
        var model = getById(id);
        return packageService.queryName(model.getPackageId());
    }

    @Override
    public void assetsRefundCall(OrderModel orderModel, UserAssetsDataModel userAssetsDataModel) {
        this.changeStatus(userAssetsDataModel.getAssetMappingId(), ProductCodeStatus.refund, null);
    }

    @Override
    public void overduePostHandler(OrderModel orderModel, UserAssetsDataModel userAssetsDataModel) {
        ProductCodeModel build = ProductCodeModel.builder().orderId(orderModel.getId()).build();
        build.setId(userAssetsDataModel.getAssetMappingId());
        this.simpleUpdate(build);
    }

    @Override
    public List<ColumnModel> getColumnList(String entityId) {
        ProductCodeModel byId = this.getById(entityId);
        if (StrUtil.isBlank(byId.getSkuId())) {
            return null;
        }
        try {
            return packageSkuService.getEffecitiveColums(byId.getSkuId()).parallelStream().peek(r -> r.setCategoryName(categoryService.queryName(r.getCategoryId()))).collect(Collectors.toList());
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public Boolean changeStatus(String code, ProductCodeStatus status, String userId) {
        try {
            RedissonLock.lock("productCode:status:" + code, k -> {
                if (productCodeMapper.update(null, Wrappers.<ProductCodeModel>lambdaUpdate()
                        .set(ProductCodeModel::getStatus, status)
                        .set(StrUtil.isNotBlank(userId), ProductCodeModel::getUserId, userId)
                        .set(StrUtil.isNotBlank(userId), ProductCodeModel::getUserTime, LocalDateTime.now())
                        .eq(ProductCodeModel::getId, code)
                        .eq(ProductCodeModel::getStatus, ProductCodeStatus.effective)) != 1) {
                    throw new BizRuntimeException(ExamResultCode.codeUneffective);
                }
            });
        } catch (Exception e) {
            throw new BizRuntimeException(ExamResultCode.codeUneffective);
        }
        return true;
    }

    @Override
    public ProductCodeModel getAndCheckByCode(String code) {
        ProductCodeModel codeModel = this.getById(code);
        if (null == codeModel) {
            throw new BizRuntimeException(ExamResultCode.productCodeNotExist);
        }
        if (ProductCodeStatus.effective.equals(codeModel.getStatus())) {
            return codeModel;
        }
        if (ProductCodeStatus.used.equals(codeModel.getStatus())) {
            throw new BizRuntimeException(ExamResultCode.productCodeHasUsed);
        }
        if (ProductCodeStatus.refund.equals(codeModel.getStatus())) {
            throw new BizRuntimeException(ExamResultCode.productCodeRefund);
        }
        return null;
    }
}
